package io.yizoo.system.controller.flow;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.elm.core.CoreController;

import java.util.*;


import io.elm.core.CoreMapper;
import io.yizoo.core.flow.FlowDesigner;
import io.yizoo.core.flow.FlowType;
import io.yizoo.system.entity.*;
import io.yizoo.system.mapper.sys_flowMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/system/flow/one_road_flow")
public class one_road_flowController extends CoreController {

    @Autowired
    private CoreMapper coreMapper;

    @Autowired
    private FlowDesigner dfTool;

    @Autowired
    private sys_flowMapper flowMapper;

    @PostMapping("/GetOneRoadFlowListPage")
    public Object GetOneRoadFlowListPage(@RequestBody String jsonStr) {
        return JsonResultPage(dfTool.GetOneRoadFlowListPage(jsonStr));
    }
    @PostMapping("/GetFlowListPage_All")
    public Object GetFlowListPage_All(@RequestBody String jsonStr) {
        return JsonResultPage(dfTool.GetFlowListPage_All(jsonStr));
    }

    @PostMapping("/GetFlowList")
    public Object GetFlowList(@RequestBody String jsonStr) {
        return dfTool.GetFlowList(jsonStr);
    }
    @PostMapping("/GetFlowCodeForCreate")
    public Object GetFlowCodeForCreate(@RequestBody String jsonStr) {
        return dfTool.GetFlowCodeForCreate(jsonStr);
    }
    @PostMapping("/GetSecForm")
    public Object GetSecForm(@RequestBody String jsonStr) {
        return dfTool.GetSecForm(jsonStr);
    }
    @PostMapping("/UpserFlowAndSecForm")
    public Object UpserFlowAndSecForm(@RequestBody String jsonStr) {
        return dfTool.UpserFlowAndSecForm(jsonStr);
    }
    @PostMapping("/UpsertFlowSecForm")
    public Object UpsertFlowSecForm(@RequestBody String jsonStr) {
        return  dfTool.UpsertFlowSecForm(jsonStr);
    }
    @PostMapping("/DeleteFlow")
    public Object DeleteFlow(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);
        String flow_id = data.get("id").asText();
        return dfTool.DeleteFlow(flow_id);
    }

    @PostMapping("/GetFlowNodeList")
    public Object GetFlowNodeList(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_id = data.get("flow_id").asText();

        List<Map<String,Object>> result = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("*")
                        .putFactorItem("flow_id",flow_id)
                        .From(fw_flow_node.class)
                        .Where("and flow_id = #{flow_id}","flow_id")
                        .GetFactor());
        return result;
    }
    @PostMapping("/GetFlowLineList")
    public Object GetFlowLineList(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_id = data.get("flow_id").asText();

        List<Map<String,Object>> result = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("*")
                        .putFactorItem("flow_id",flow_id)
                        .From(fw_flow_line.class)
                        .Where("and flow_id = #{flow_id}","flow_id")
                        .GetFactor());
        return result;
    }

    @PostMapping("/GetDataForNodeCheckEdit")
    public Object GetDataForNodeCheckEdit() {
        return dfTool.GetDataForNodeCheckEdit();
    }

    @PostMapping("/GetNodeCheckData")
    public Object GetNodeCheckData(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String node_id = data.get("id").asText();
        return dfTool.GetNodeCheckData(node_id);
    }

    @PostMapping("/UpsertOneNode_OneRoadFLow")
    @Transactional
    public Object UpsertOneNode_OneRoadFLow(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        JsonNode nodeData = data.get("node");
        ArrayNode nodeCheckList = (ArrayNode)data.get("node_check");
        ArrayNode nodeCheckParamList = (ArrayNode)data.get("node_check_param");

        String flow_id = nodeData.get("flow_id").asText();
        String flow_node_id = nodeData.get("id").asText();

        //组装待节点数据
        fw_flow_node nodeModel = new fw_flow_node();
        nodeModel.setId(flow_node_id);
        nodeModel.setFlow_id(flow_id);
        nodeModel.setTitle(nodeData.get("title").asText());
        nodeModel.setNode_type(FlowType.node_type_normal);
        nodeModel.setNode_url(FlowType.getJsonNodeItemTextNull(nodeData,"node_url"));
        nodeModel.setNode_alias(FlowType.getJsonNodeItemTextNull(nodeData,"node_alias"));
        nodeModel.setUser_policy(FlowType.getJsonNodeItemTextNull(nodeData,"user_policy"));
        nodeModel.setNode_policy(FlowType.getJsonNodeItemTextNull(nodeData,"node_policy"));
        nodeModel.setEe_ff_item(FlowType.getJsonNodeItemTextNull(nodeData,"ee_ff_item"));
        nodeModel.setPb_policy(FlowType.node_pb_policy_toFirst_eJump);
        //组装节点参与者接口数据
        List<fw_flow_node_check> nodeCheckModelList = new ArrayList<fw_flow_node_check>();
        List<fw_flow_node_check_param> nodeCheckParamModelList = new ArrayList<fw_flow_node_check_param>();
        for (JsonNode item : nodeCheckList) {
            fw_flow_node_check nodeCheckModel = new fw_flow_node_check();
            nodeCheckModel.setId(item.get("id").asText());
            nodeCheckModel.setFlow_id(flow_id);
            nodeCheckModel.setFlow_node_id(flow_node_id);
            nodeCheckModel.setIface_id(item.get("iface_id").asText());
            nodeCheckModelList.add(nodeCheckModel);
        }
        for (JsonNode item : nodeCheckParamList) {
            fw_flow_node_check_param nodeCheckParamModel = new fw_flow_node_check_param();
            nodeCheckParamModel.setId(item.get("id").asText());
            nodeCheckParamModel.setFlow_id(flow_id);
            nodeCheckParamModel.setFlow_node_id(flow_node_id);
            nodeCheckParamModel.setCheck_id(item.get("check_id").asText());
            nodeCheckParamModel.setValue(FlowType.getJsonNodeItemTextNull(item,"value"));
            nodeCheckParamModel.setFlow_param_id(FlowType.getJsonNodeItemTextNull(item,"flow_param_id"));
            nodeCheckParamModel.setIface_param_id(FlowType.getJsonNodeItemTextNull(item,"iface_param_id"));
            nodeCheckParamModelList.add(nodeCheckParamModel);
        }

        List<fw_flow_line> lineModelList=new ArrayList<fw_flow_line>();

        //检查流程是否有开始结束节点，如果没有那么组装开始结束两节点和相应连线的数据
        boolean nodeStartEndExist = false;
        boolean startNodeExist = false;
        boolean endNodeExist = false;
        String end_node_id = null;
        List<fw_flow_node> nodeStartEndModelList=new ArrayList<fw_flow_node>();
        List<Map<String,Object>> check = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("id,node_type")
                        .putFactorItem("flow_id",flow_id)
                        .From(fw_flow_node.class)
                        .Where("and flow_id = #{flow_id} and node_type not in ('"+ FlowType.node_type_normal+"')","flow_id")
                        .GetFactor());
        for(Map<String,Object> ccc : check){
            if(ccc.get("node_type").toString().equals(FlowType.node_type_start)){
                startNodeExist =true;
            }
            if(ccc.get("node_type").toString().equals(FlowType.node_type_end)){
                endNodeExist =true;
                end_node_id = ccc.get("id").toString();
            }
        }
        nodeStartEndExist = startNodeExist && endNodeExist;
        if(!nodeStartEndExist){//若出现缺少开始节点或结束节点的情况，为避免数据混乱，先删除开始结束节点，然后重新添加
            Ctor.CoreMapper.UDelete(
                    Ctor.DMaker().Deleter
                            .putFactorItem("flow_id",flow_id)
                            .From(fw_flow_node.class)
                            .Where("AND flow_id = #{flow_id} AND node_type IN ('start','end')", "flow_id")
                            .GetFactor());

            fw_flow_node startNodeModel = new fw_flow_node();
            startNodeModel.setId(UUID.randomUUID().toString());
            startNodeModel.setFlow_id(flow_id);
            startNodeModel.setNode_type(FlowType.node_type_start);
            startNodeModel.setTitle("开始");
            nodeStartEndModelList.add(startNodeModel);

            fw_flow_node endNodeModel = new fw_flow_node();
            endNodeModel.setId(UUID.randomUUID().toString());
            endNodeModel.setFlow_id(flow_id);
            endNodeModel.setNode_type(FlowType.node_type_end);
            endNodeModel.setTitle("结束");
            nodeStartEndModelList.add(endNodeModel);

            fw_flow_line lineFromStart = null;

            lineFromStart = new fw_flow_line();
            lineFromStart.setId(UUID.randomUUID().toString());
            lineFromStart.setFlow_id(flow_id);
            lineFromStart.setStart_node(startNodeModel.getId());
            lineFromStart.setEnd_node(nodeModel.getId());
            lineModelList.add(lineFromStart);

            fw_flow_line linetoEnd = new fw_flow_line();
            linetoEnd.setId(UUID.randomUUID().toString());
            linetoEnd.setFlow_id(flow_id);
            linetoEnd.setStart_node(nodeModel.getId());
            linetoEnd.setEnd_node(endNodeModel.getId());
            lineModelList.add(linetoEnd);
        }

        if(!nodeStartEndExist){
            //若开始结束节点未入库，那么前面已经组装好相关连线数据
        }
        else{
            //检查本节点是否已在数据库中，若没有，则需将本节点放在结束节点之前（即处理相关连线）
            List<Map<String,Object>> tCheck = Ctor.CoreMapper.USelect(
                    Ctor.DMaker().Selector
                            .Select("id")
                            .putFactorItem("flow_node_id",flow_node_id)
                            .From(fw_flow_node.class)
                            .Where("and id = #{flow_node_id}","flow_node_id")
                            .GetFactor());
            if(tCheck.size()==0){
                List<Map<String,Object>> lineCheck = Ctor.CoreMapper.USelect(
                        Ctor.DMaker().Selector
                                .Select("id")
                                .putFactorItem("flow_id",flow_id)
                                .putFactorItem("end_node_id",end_node_id)
                                .From(fw_flow_line.class)
                                .Where("and flow_id = #{flow_id} and end_node = #{end_node_id}","flow_id","end_node_id")
                                .GetFactor());
                if(lineCheck.size()>0){
                    fw_flow_line linetoNode = new fw_flow_line();
                    linetoNode.setId(lineCheck.get(0).get("id").toString());
                    linetoNode.setEnd_node(flow_node_id);
                    lineModelList.add(linetoNode);
                }
                fw_flow_line linetoEnd = new fw_flow_line();
                linetoEnd.setId(UUID.randomUUID().toString());
                linetoEnd.setFlow_id(flow_id);
                linetoEnd.setStart_node(nodeModel.getId());
                linetoEnd.setEnd_node(end_node_id);
                lineModelList.add(linetoEnd);
            }
        }

        //更新数据库
        Ctor.HMapper.Upsert(nodeModel);
        if(nodeCheckModelList.size()>0){
            Ctor.HMapper.Save(nodeCheckModelList,Ctor.DMaker().Deleter
                    .putFactorItem("flow_node_id",flow_node_id)
                    .From(fw_flow_node_check.class)
                    .Where("and flow_node_id=#{flow_node_id}","flow_node_id")
                    .GetFactor());
        }
        if(nodeCheckParamModelList.size()>0){
            Ctor.HMapper.Save(nodeCheckParamModelList,Ctor.DMaker().Deleter
                    .putFactorItem("flow_node_id",flow_node_id)
                    .From(fw_flow_node_check_param.class)
                    .Where("and flow_node_id=#{flow_node_id}","flow_node_id")
                    .GetFactor());
        }
        if(lineModelList.size()>0){
            Ctor.HMapper.Save(lineModelList,Ctor.DMaker().Deleter
                    .putFactorItem("flow_id",flow_id)
                    .From(fw_flow_line.class)
                    .Where("and flow_id=#{flow_id} and (start_node NOT IN (select id from fw_flow_node) or end_node NOT IN (select id from fw_flow_node))","flow_id")
                    .GetFactor());
        }
        if(nodeStartEndModelList.size()>0){Ctor.HMapper.Save(nodeStartEndModelList,null);}

        return true;
    }

    //交换两个节点的位置，只涉及连线修改
    @PostMapping("/TurnTwoNode")
    @Transactional
    public Object TurnTwoNode(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String aa_node_id = data.get("aa_node_id").asText();
        String bb_node_id = data.get("bb_node_id").asText();

        List<Map<String,Object>> nodeDataList = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("id,flow_id")
                        .putFactorItem("aa_node_id",aa_node_id)
                        .putFactorItem("bb_node_id",bb_node_id)
                        .From(fw_flow_node.class)
                        .Where("and (id=#{aa_node_id} or id=#{bb_node_id})","aa_node_id","bb_node_id")
                        .GetFactor());
        if(nodeDataList.size()!=2
                || !(nodeDataList.get(0).get("flow_id").toString()).equals(nodeDataList.get(1).get("flow_id").toString())){
            return false;
        }

        List<Map<String,Object>> lineDataList = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("id,start_node,end_node")
                        .putFactorItem("aa_node_id",aa_node_id)
                        .putFactorItem("bb_node_id",bb_node_id)
                        .From(fw_flow_line.class)
                        .Where("and (start_node=#{aa_node_id} or end_node=#{aa_node_id} or start_node=#{bb_node_id} or end_node=#{bb_node_id})","aa_node_id","bb_node_id")
                        .GetFactor());

        List<fw_flow_line> lineModelList=new ArrayList<fw_flow_line>();
        for(Map<String,Object> lineData : lineDataList){
            fw_flow_line lineModel = new fw_flow_line();
            lineModel.setId(lineData.get("id").toString());
            if(lineData.get("start_node").toString().equals(aa_node_id)){
                lineModel.setStart_node(bb_node_id);
            }
            if(lineData.get("end_node").toString().equals(aa_node_id)){
                lineModel.setEnd_node(bb_node_id);
            }
            if(lineData.get("start_node").toString().equals(bb_node_id)){
                lineModel.setStart_node(aa_node_id);
            }
            if(lineData.get("end_node").toString().equals(bb_node_id)){
                lineModel.setEnd_node(aa_node_id);
            }
            lineModelList.add(lineModel);
        }

        Ctor.HMapper.Save(lineModelList,null);

        return true;
    }

    @PostMapping("/DeleteNode_OneRoadFLow")
    public Object DeleteNode_OneRoadFLow(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);
        String node_id = data.get("id").asText();

        List<Map<String,Object>> lineDataList = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .Select("id,flow_id,start_node,end_node")
                        .putFactorItem("node_id",node_id)
                        .From(fw_flow_line.class)
                        .Where("AND (start_node = #{node_id} OR end_node = #{node_id}) ", "node_id")
                        .GetFactor());
        fw_flow_line lineModel = new fw_flow_line();
        if(lineDataList.size()==2){
            lineModel.setId(UUID.randomUUID().toString());
            lineModel.setFlow_id(lineDataList.get(0).get("flow_id").toString());
            for(Map<String,Object> lineData : lineDataList){
                if(node_id.equals(lineData.get("start_node"))){
                    lineModel.setEnd_node(lineData.get("end_node").toString());
                }
                else if(node_id.equals(lineData.get("end_node"))){
                    lineModel.setStart_node(lineData.get("start_node").toString());
                }
            }
        }

        if(lineModel.getStart_node()!=null && lineModel.getEnd_node()!=null){
            boolean result = dfTool.DeleteNode(node_id);
            if(result){ Ctor.HMapper.Upsert(lineModel); }
            return result;
        }
        else{ return false; }
    }

}
